#include <stdio.h>
#include <signal.h>
#include "sys.h"
#include "Common_Types.h"
#include "stdlib.h"
#include "stdarg.h"

void message(int priority, const char * format, ...)
{
	va_list ap;
	va_start(ap, format);


	fprintf(stderr, "(CL %s) ",
		priority == LOG_EMERG ? "emergency" :
		priority == LOG_ALERT ? "alert" :
		priority == LOG_CRIT ? "critical" :
		priority == LOG_ERR ? "error" :
		priority == LOG_WARNING ? "warning" :
		priority == LOG_NOTICE ? "notice" :
		priority == LOG_INFO ? "info" :
		priority == LOG_DEBUG ? "debug" :
		"???");
	vfprintf(stderr, format, ap);

	va_end(ap);
}

TimeInternal subtractTime(const TimeInternal* t1, const TimeInternal* t2)
{

	TimeInternal result;
    if((t1->seconds < t2->seconds) ||
    		((t1->seconds == t2->seconds) &&
    				(t1->nanoseconds <= t2->nanoseconds) ))
    {
    	result.seconds = 0;
		result.nanoseconds = 0;
    }
    else {
    	result.seconds = t1->seconds - t2->seconds;
    	if(t1->nanoseconds < t2->nanoseconds) {
    		result.nanoseconds = t1->nanoseconds + 1000000000 - t2->nanoseconds;
    		result.seconds--;
    	}
    	else {
    		result.nanoseconds = t1->nanoseconds - t2->nanoseconds;
    	}
    }
    return result;
}
TimeInternal addTime(const TimeInternal* t1, const TimeInternal* t2)
{
	TimeInternal result;
	result.nanoseconds = t1->nanoseconds + t2->nanoseconds;
	result.seconds     = t1->seconds     + t2->seconds;

	if(result.nanoseconds >= 1000000000  )
	{
		result.nanoseconds -= 1000000000;
		result.seconds++;
	}
	return result;
}
/*return 0 if t1 is greater than t2 *
 *return 1 if t2 is greater than t1 */
BOOL greaterThan(const TimeInternal* t1, const TimeInternal* t2)
{

	return (( t1->seconds == t2->seconds) ?
			((t1)->nanoseconds > (t2->nanoseconds)):((t1)->seconds > (t2)->seconds));
}
BOOL nanoSleep(TimeInternal* t)
{
	struct timespec ts, tr;

	ts.tv_sec = t->seconds;
	ts.tv_nsec = t->nanoseconds;

	if (nanosleep(&ts, &tr) < 0) {
		t->seconds = tr.tv_sec;
		t->nanoseconds = tr.tv_nsec;
		return FALSE;
	}
	return TRUE;
}
void getTime(TimeInternal* time)
{

	#if defined(linux)
		struct timespec tp;
		if (clock_gettime(CLOCK_REALTIME, &tp) < 0) {
			PERROR("clock_gettime() failed, exiting.");
			return;
		}
		time->seconds = tp.tv_sec;
		time->nanoseconds = tp.tv_nsec;
	#elif defined(__CYGWIN__)
		struct timespec tp;
		if (clock_gettime(CLOCK_REALTIME, &tp) < 0) {
			PERROR("clock_gettime() failed, exiting.");
			return;
		}
		time->seconds = tp.tv_sec;
		time->nanoseconds = tp.tv_nsec;
	#elif defined(__APPLE__)
		struct timeval tv;
		gettimeofday(&tv, 0);
		time->seconds = tv.tv_sec;
		time->nanoseconds = tv.tv_usec * 1000;
	#else  /*WINDOWS*/
		/*
		struct timespec tp;
		if (clock_gettime(CLOCK_REALTIME, &tp) < 0) {
			PERROR("clock_gettime() failed, exiting.");
			exit(0);
		}
		time->seconds = tp.tv_sec;
		time->nanoseconds = tp.tv_nsec;*/

		time->seconds = 0;
		time->nanoseconds = 0;
	#endif /* linux || __APPLE__ */
}



#define TIMER_INTERVAL 1
unsigned int elapsed;
void catch_alarm(int sig)
{
	elapsed++;
}

void initTimer(void)
{
	struct itimerval itimer;

	DBG("initTimer\n");

	signal(SIGALRM, SIG_IGN);

	elapsed = 0;
	itimer.it_value.tv_sec = itimer.it_interval.tv_sec = 5;
	itimer.it_value.tv_usec = itimer.it_interval.tv_usec = 0;//TIMER_INTERVAL;

	signal(SIGALRM, catch_alarm);
	setitimer(ITIMER_REAL, &itimer, 0);
}

void timerUpdate(IntervalTimer * itimer)
{

	int i, delta;

	delta = elapsed;
	elapsed = 0;

	if (delta <= 0)
		return;

	for (i = 0; i < INTERVAL_TIMER_SIZE; ++i) {
		if ((itimer[i].interval) > 0 && ((itimer[i].left) -= delta)
		    <= 0) {
			itimer[i].left = itimer[i].interval;
			itimer[i].expire = TRUE;
			DBG("timerUpdate: timer %u expired\n", i);
		}
	}

}

void timerStop(U16 index, IntervalTimer * itimer)
{
	if (index >= INTERVAL_TIMER_SIZE)
		return;

	itimer[index].interval = 0;
}

void timerStart(U16 index, U16 interval, IntervalTimer * itimer)
{
	if (index >= INTERVAL_TIMER_SIZE)
		return;

	itimer[index].expire = FALSE;
	itimer[index].left = interval;
	itimer[index].interval = itimer[index].left;

	DBG("timerStart: set timer %d to %d\n", index, interval);
}

BOOL timerExpired(U16 index, IntervalTimer * itimer)
{
	timerUpdate(itimer);

	if (index >= INTERVAL_TIMER_SIZE)
		return FALSE;

	if (!itimer[index].expire)
		return FALSE;

	itimer[index].expire = FALSE;

	return TRUE;
}

